package com.liuhm.dianjuhe.utils;

import com.liuhm.csvdemo.dianjuhe.bean.*;
import com.liuhm.dianjuhe.bean.*;

import java.util.*;

/**
 * @author liuhaomin
 * @date 2020/9/14
 */
public class ClusterOverlay {

    /** 前端map.getZoom() */
    private static int zoom=1;
    /** 自定义多少像素聚合*/
    private static int mClusterSize=80;
    /** 表示当前缩放比例下，每像素代表的实际地图距离（单位米）*/
//    private static double mPXInMeters=58.619102;
    private static boolean mIsCanceled = false;
    /** 前端map.getResolution() * mClusterSize    */
    public static double getmClusterDistance(double mPXInMeters) {
        return mPXInMeters * mClusterSize;
    }

    public static List<Cluster> setOrgClusters(List<Map<String, Object>> list, double mPXInMeters, LatLngBounds visibleBounds, Integer zoom, boolean isLattice){
        long oldNow=System.currentTimeMillis();
        System.out.println("开始时间"+oldNow);
        List<ClusterItem> mClusterItems=new ArrayList<>();
        List<Cluster> mClusters=new ArrayList<>();;
        calculateOrgClusters(visibleBounds,list,mClusters,getmClusterDistance(mPXInMeters),zoom,isLattice);
        long now=System.currentTimeMillis();
        long result=now-oldNow;
        System.out.println("map计算的总时间"+result);
        return mClusters;
    }

    public static List<Cluster> setClusters(List<Map<String, Object>> list, double mPXInMeters, LatLngBounds visibleBounds,Integer zoom, boolean isLattice){
        long oldNow=System.currentTimeMillis();
        System.out.println("开始时间"+oldNow);
        List<ClusterItem> mClusterItems=new ArrayList<>();
        List<Cluster> mClusters=new ArrayList<>();;
        list.forEach(data->{
            LatLng mLatLng=new LatLng(Double.parseDouble(data.get("lat").toString()),Double.parseDouble(data.get("lng").toString()));
            ClusterItem clusterItem=new RegionItem(mLatLng,data);
            mClusterItems.add(clusterItem);
        });
        long ss=System.currentTimeMillis();
        System.out.println("11始时间"+ss);
        System.out.println("map清洗数据花费的时间"+(ss-oldNow));
        calculateClusters(visibleBounds,mClusterItems,mClusters,getmClusterDistance(mPXInMeters),zoom,isLattice);
        long now=System.currentTimeMillis();
        long result=now-oldNow;
        System.out.println("map计算时间"+(now-ss));
        System.out.println("map计算的总时间"+result);
        return mClusters;
    }
    public static MapResult setMapClusters(List<Map<String, Object>> list, double mPXInMeters, LatLngBounds visibleBounds,Integer zoom, boolean isLattice){
        long oldNow=System.currentTimeMillis();
        List<ClusterItem> mClusterItems=new ArrayList<>();
        List<Cluster> mClusters=new ArrayList<>();;
        list.forEach(data->{
            LatLng mLatLng=new LatLng(Double.parseDouble(data.get("lat").toString()),Double.parseDouble(data.get("lng").toString()));
            ClusterItem clusterItem=new RegionItem(mLatLng,data);
            mClusterItems.add(clusterItem);
        });

        calculateClusters(visibleBounds,mClusterItems,mClusters,getmClusterDistance(mPXInMeters),zoom,isLattice);
        long now=System.currentTimeMillis();
        long result=now-oldNow;
        System.out.println(result);
        MapResult mapResult=new MapResult();
        Integer total=0;
        for (Cluster mCluster : mClusters) {
            total+= mCluster.getCount();
        }
        mapResult.setClusters(mClusters);
        mapResult.setTotal(total);
        return mapResult;
    }
    /**
     *
     * @param   visibleBounds 屏幕的范围 前端传
     * @param   list 所有的点数据
     * @param   mClusters 聚合后的数据集合
     * @param   isLattice 是否是方格和距离的算法 ， 是 方格和距离的算法   ， 否 距离算法
     * @return
     */
    private static void calculateOrgClusters(LatLngBounds visibleBounds,List<Map<String, Object>> list,List<Cluster> mClusters,double mClusterDistance,Integer zoom,boolean isLattice) {
        mIsCanceled = false;
        mClusters.clear();
        ClusterItem clusterItem=new RegionItem();
        LatLng mLatLng;
//        for (Map<String, Object> data: list) {
         for (int i=0;i<list.size();i++){
                Map<String, Object>  data=list.get(i);
             mLatLng=new LatLng(Double.parseDouble(data.get("lat").toString()),Double.parseDouble(data.get("lng").toString()));
            clusterItem=new RegionItem(mLatLng,data);
            if (mIsCanceled) {
                return;
            }
            LatLng latlng = clusterItem.getPosition();
            if (visibleBounds.contains(latlng)) {
                Cluster cluster =null;
                if(isLattice){
                    cluster = getClusterFangGe(latlng,mClusters);
                }else {
                    cluster = getCluster(latlng,mClusters,mClusterDistance,zoom);
                }

                if (cluster != null) {
                    cluster.addCount();
                } else {
                    cluster = new Cluster(latlng);
                    mClusters.add(cluster);
                    cluster.addClusterItem(clusterItem);
                    cluster.addCount();
                    // 设置中心点的范围
                    if(isLattice){
                        LatLngBounds latLngBounds = AMapUtils.getAround(latlng, mClusterDistance);
                        cluster.setLatLngBounds(latLngBounds);
                    }
                }
            }
        }
    }
    /**
      *
      * @param   visibleBounds 屏幕的范围 前端传
      * @param   mClusterItems 所有的点数据
      * @param   mClusters 聚合后的数据集合
      * @param   isLattice 是否是方格和距离的算法 ， 是 方格和距离的算法   ， 否 距离算法
      * @return
      */
    private static void calculateClusters(LatLngBounds visibleBounds,List<ClusterItem> mClusterItems,List<Cluster> mClusters,double mClusterDistance,Integer zoom,boolean isLattice) {
        mIsCanceled = false;
        mClusters.clear();
        for (ClusterItem clusterItem : mClusterItems) {
            if (mIsCanceled) {
                return;
            }
            LatLng latlng = clusterItem.getPosition();
            if (visibleBounds.contains(latlng)) {
                Cluster cluster =null;
                if(isLattice){
                    cluster = getClusterFangGe(latlng,mClusters);
                }else {
                    cluster = getCluster(latlng,mClusters,mClusterDistance,zoom);
                }

                if (cluster != null) {
                    cluster.addCount();
                } else {
                    cluster = new Cluster(latlng);
                    mClusters.add(cluster);
                    cluster.addClusterItem(clusterItem);
                    cluster.addCount();
                    // 设置中心点的范围
                    if(isLattice){
                        LatLngBounds latLngBounds = AMapUtils.getAround(latlng, mClusterDistance);
                        cluster.setLatLngBounds(latLngBounds);
                    }
                }
            }
        }
    }

    /**
     * 距离算法
     * 根据一个点获取是否可以依附的聚合点，没有则返回null
     * @param latLng 判断该点是不是属于聚合中的一个点
     * @param clusters 所有的聚合点
     * @param mClusterDistance 大小
     * @return
     */
    private static Cluster getCluster(LatLng latLng,List<Cluster> clusters,Double mClusterDistance,Integer zoom) {
        for (Cluster cluster : clusters) {
            LatLng clusterCenterPoint = cluster.getCenterLatLng();
            double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint);
            if (distance < mClusterDistance && zoom < 19) {
                return cluster;
            }
        }
        return null;
    }
    /**
     * 方格和距离算法
     * 根据一个点获取是否可以依附的聚合点，没有则返回null
     * @param latLng 判断该点是不是属于聚合中的一个点
     * @param clusters 所有的聚合点
     * @return
     */
    private static Cluster getClusterLattice(LatLng latLng,List<Cluster> clusters,Integer zoom) {
        Cluster result=null;
        Double resultDistance=0D;
        for (Cluster cluster : clusters) {
            LatLng clusterCenterPoint = cluster.getCenterLatLng();
            if (cluster.getLatLngBounds().contains(latLng)) {
                double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint);
                if(result==null){
                    result=cluster;
                    resultDistance=distance;
                }else{
                    if (distance < resultDistance && zoom < 19) {
                        result=cluster;
                        resultDistance=distance;
                    }
                }
            }
        }
        return result;
    }
    /**
     * 方格和距离算法
     * 根据一个点获取是否可以依附的聚合点，没有则返回null
     * @param latLng 判断该点是不是属于聚合中的一个点
     * @param clusters 所有的聚合点
     * @return
     */
    private static Cluster getClusterFangGe(LatLng latLng,List<Cluster> clusters) {
        for (Cluster cluster : clusters) {
            if (cluster.getLatLngBounds().contains(latLng)) {
                return cluster;
            }
        }
        return null;
    }

    /**
     * 在已有的聚合基础上，对添加的单个元素进行聚合
     *
     * @param clusterItem
     */
    private static void calculateSingleCluster(ClusterItem clusterItem,LatLngBounds visibleBounds,List<Cluster> mClusters,Integer zoom,Double mClusterDistance) {
        LatLng latlng = clusterItem.getPosition();
        if (!visibleBounds.contains(latlng)) {
            return;
        }
        Cluster cluster = getCluster(latlng,mClusters,mClusterDistance,zoom);
        if (cluster != null) {
            cluster.addClusterItem(clusterItem);
        } else {
            cluster = new Cluster(latlng);
            mClusters.add(cluster);
            cluster.addClusterItem(clusterItem);

        }
    }
}